#ifndef MAPNIK_XML_ATTRIBUTE_CAST_HPP
#define MAPNIK_XML_ATTRIBUTE_CAST_HPP

#include "xml_tree.hpp"
#include "xml_conv.hpp"

// stl
#include <string>
#include <map>
#include <typeinfo>
#include <utility>
#include <stdexcept>

namespace mp
{
	namespace xml
	{
		template <typename T>
		struct do_xml_attribute_cast
		{
			static inline bool xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& /*source*/, T& result)
			{
				std::string err_msg("No conversion from std::string to");
				err_msg += std::string(typeid(T).name());
				throw std::runtime_error(err_msg);
				return false;
			}
		};
				
		// specialization for bool
		template <>
		struct do_xml_attribute_cast<bool>
		{
			static inline bool xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source, bool& result)
			{
				result=false;
				if (source=="1"||source=="true"||source=="TRUE"||source=="True")
				{
					result=true;
				}
				return true;
			}
		};

		// specialization for int
		template <>
		struct do_xml_attribute_cast<int>
		{
			static inline bool xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source, int& result)
			{
				if (string2int(source, result))
					return true;
				return false;
			}
		};

		// specialization for unsigned

		template <>
		struct do_xml_attribute_cast<unsigned>
		{
			static inline bool xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source,unsigned& result)
			{
				if (string2uint(source, result))
					return true;
				return false;
			}
		};

		template <>
		struct do_xml_attribute_cast<xml_color>
		{
			static inline bool xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source,xml_color& result)
			{
				if (string2color(source, result))
					return true;
				return false;
			}
		};

		// specialization for float
		template <>
		struct do_xml_attribute_cast<float>
		{
			static inline bool xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source, float& result)
			{
				if (string2float(source, result))
					return true;
				return false;
			}
		};

		// specialization for double
		template <>
		struct do_xml_attribute_cast<double>
		{
			static inline bool xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source, double& result)
			{
				if (string2double(source, result))
					return true;
				return false;
			}
		};

		// specialization for std::string
		template <>
		struct do_xml_attribute_cast<std::string>
		{
			static inline bool xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source, std::string& result)
			{
				result = (source);
				return true;
			}
		};

		template <typename T>
		bool xml_attribute_cast(xml_tree const& tree, std::string const& source,T& result)
		{
			return do_xml_attribute_cast<T>::xml_attribute_cast_impl(tree, source, result);
		}
	} 
} 
#endif // MAPNIK_XML_ATTRIBUTE_CAST_HPP
